home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / util / cdity / MRQ.lha / MRQ / Source / mrq.c < prev    next >
C/C++ Source or Header  |  2000-10-16  |  22KB  |  770 lines

  1. /* mrq.c
  2. ** Main program source for MRQ, the MUI Requester Improver
  3. **
  4. ** ©1997-2000 by Matthias.Bethke <Matthias.Bethke@gmx.net>
  5. ** You are free to modify this source or use parts of it in your
  6. ** own programs as long as they are distributed as freeware.
  7. */
  8.  
  9. /* $Id: mrq.c 1.4 2000/03/30 23:17:52 msbethke Exp $
  10. **
  11. ** $Log: mrq.c $
  12. ** Revision 1.4  2000/03/30 23:17:52  msbethke
  13. ** Changed NewImage.mcc -> Guigfx.mcc
  14. **
  15. ** Revision 1.3  2000/02/16 18:25:42  msbethke
  16. ** Disabled DOS requesters for MRQ's main process to avoid deadlocks
  17. **
  18. ** Revision 1.2  2000/01/25 17:28:05  msbethke
  19. ** Adapted to new header names
  20. **
  21. ** Revision 1.1  2000/01/25 16:43:18  msbethke
  22. ** Initial revision
  23. **
  24. */
  25.  
  26. #include <proto/icon.h>
  27. #include <proto/intuition.h>
  28. #include <proto/rexxsyslib.h>
  29. #include <proto/commodities.h>
  30. #include <proto/datatypes.h>
  31. #include <proto/wbstart.h>
  32. #include <clib/debug_protos.h>
  33. #include <libraries/reqtools.h>
  34. #include <guigfx/guigfx.h>
  35. #include <exec/memory.h>
  36. #include <dos/dostags.h>
  37. #include <lib/mb_utils.h>
  38. #include <MUI/Guigfx_mcc.h>
  39. #include <dos.h>
  40. #include <stdarg.h>
  41. #include <string.h>
  42. #include <stdlib.h>
  43. #include <ctype.h>
  44. #include "mrq.h"
  45. #include "config.h"
  46. #include "mui_macros.h"
  47. #include "muistuff.h"
  48. #include "Requesters.h"
  49. #include "MRQasm.h"
  50. #include "mrqwindowclass.h"
  51.  
  52. #define RTEZREQUESTA_OFFSET (-66)
  53. #define EASYREQUESTARGS_OFFSET (-588)
  54.  
  55. #define GUIGFXLIB_NAME "guigfx.library"
  56. #define GUIGFXLIB_VMIN 15
  57. #define REQTOOLSLIB_NAME "reqtools.library"
  58. #define REQTOOLSLIB_VMIN 0
  59. #define CGFXLIB_NAME "cybergraphics.library"
  60. #define CGFXLIB_VMIN 0
  61.  
  62. /*************************************************************************/
  63. /* local protos & dummy functions                                        */
  64. /*************************************************************************/
  65. static BOOL OpenLibs(void);
  66. static void CloseLibs(void);
  67. static BOOL BuildApp(void);
  68. static void DisposeApp(APTR app);
  69. static APTR ReadToolTypes(struct WBStartup*);
  70. static APTR ReadShellParams(void);
  71. static STRPTR FindConfigFile(void);
  72. static BOOL CheckDir(STRPTR);
  73. static BOOL AskQuit(void);
  74. static BOOL CheckPatchManager(void);
  75. static LONG DecodeQuality(STRPTR);
  76. static void StartExternalProgram(STRPTR);
  77. static BOOL ExistsIcon(STRPTR);
  78. static BOOL CreateCustomClasses(void);
  79. static void DeleteCustomClasses(void);
  80. /* dummies */
  81. void __regargs _CXBRK(void) {}
  82. void chkabort(void) {}
  83.  
  84.  
  85. /*************************************************************************/
  86. /* global identifiers                                                    */
  87. /*************************************************************************/
  88. APTR OldEasyRequestArgs, OldrtEZRequestA, Application;
  89. struct MUI_CustomClass *MUIMRQWindowClass;
  90. struct IClass *MRQWindowClass;
  91. UBYTE ProgName[80]={0};
  92. struct TTVars ttVars = {0};
  93. struct MRQConfig *Config;
  94. const UBYTE VersionString[]="$VER: MRQ 2.1 by M.Bethke "__AMIGADATE__;
  95. struct Library *MUIMasterBase, *GuiGFXBase, *CyberGfxBase;
  96. struct ReqToolsBase *ReqToolsBase;
  97. struct MsgPort *MainPort;
  98. LONG AppActive=TRUE;
  99. LONG __stack = 12288;
  100. BPTR _debugfh=NULL;
  101. STRPTR true_s="TRUE", false_s="FALSE",
  102.          none_s="<none>", unset_s="<unset>";    // take some work off the stringmerger
  103. /*************************************************************************/
  104. /* hooks                                                                 */
  105. /*************************************************************************/
  106. static void __saveds __asm __interrupt BrokerHookFunc(register __a1 CxMsg*, register __a2 APTR);
  107. struct Hook BrokerHook = {{NULL,NULL},(void*)(&BrokerHookFunc),NULL,NULL};
  108.  
  109.  
  110.  
  111. /*************************************************************************/
  112.  
  113. LONG main(int argc, char *argv[])
  114. {
  115. LONG rcode = RETURN_OK;
  116. APTR Args;
  117. STRPTR ConfigName;
  118. static const UBYTE MRQRendezvousPort[] = "MRQ.Rendezvous";
  119. struct Process *MyProc;
  120. APTR MyWindowPtr;
  121.  
  122.     if(!GetProgramName(ProgName,sizeof(ProgName))) strcpy(ProgName,"MRQ");
  123.  
  124.     MyProc = (struct Process*)FindTask(NULL);
  125.     MyWindowPtr = MyProc->pr_WindowPtr;
  126.     MyProc->pr_WindowPtr = (APTR)-1;
  127.  
  128.     if(FindPort((STRPTR)MRQRendezvousPort))
  129.     {
  130.         if(argc)
  131.         {
  132.             Printf("%s: already running!\n",*argv);
  133.         } else
  134.         {
  135.         struct EasyStruct es={sizeof(struct EasyStruct),0,"MRQ Error","Please don't start me twice!","I won't!"};
  136.  
  137.             EasyRequestArgs(NULL,&es,NULL,NULL);
  138.         }
  139.         return RETURN_WARN;
  140.     }
  141.  
  142.     if(argc)    Args = ReadShellParams();
  143.     else Args = ReadToolTypes((struct WBStartup*)argv);
  144.  
  145.     if(!Args) return RETURN_FAIL;
  146.  
  147.     if(!(ConfigName = FindConfigFile()))
  148.     {
  149.     struct EasyStruct es={sizeof(struct EasyStruct),0,"MRQ Error","Can't find config file!","I see"};
  150.  
  151.         EasyRequestArgs(NULL,&es,NULL,NULL);
  152.         if(argc) FreeArgs((struct RDArgs*)Args);
  153.         else FreeDiskObject((struct DiskObject*)Args);
  154.         return RETURN_ERROR;
  155.     }
  156.  
  157.     if(ttVars.DefImageDir == NULL || (!CheckDir(ttVars.DefImageDir)))
  158.     {
  159.         if(!CheckDir(ttVars.DefImageDir="PROGDIR:MRQ-images"))
  160.         {
  161.             if(!CheckDir(ttVars.DefImageDir="s:MRQ-images"))
  162.             {
  163.             struct EasyStruct es={sizeof(struct EasyStruct),0,"MRQ Error","Can't find image directory!","I see"};
  164.  
  165.                 EasyRequestArgs(NULL,&es,NULL,NULL);
  166.                 if(argc) FreeArgs((struct RDArgs*)Args);
  167.                 else FreeDiskObject((struct DiskObject*)Args);
  168.                 return RETURN_ERROR;
  169.             }
  170.         }
  171.     }
  172.  
  173.     if(ttVars.Debug)                                    // debug info wanted
  174.     {
  175.         if(!argc || strlen(ttVars.Debug))        // WB-start or file specified
  176.         {
  177.             _debugfh=Open(strlen(ttVars.Debug) ?
  178.                                 ttVars.Debug :                // file specified
  179.                                 (STRPTR)"CON:40/80/640/180/MRQ_CONSOLE",MODE_NEWFILE);    // default
  180.         } else
  181.         {
  182.             _debugfh = Output();                        // use stdout
  183.         }
  184.     }
  185.  
  186.     prdebug(    "Started %s\n\n"
  187.                 "Parameters read:\n\tCONFIGFILE    : %s\n\tMOUSEREQ      : %s\n\t"
  188.                 "SAMEWIDTH     : %s\n\tFRONTSCREEN   : %s\n\tTRANSPARENCY  : %s\n\t"
  189.                 "SINGLEFRAME   : %s\n\tSIZEABLE      : %s\n\tCENTERTEXT    : %s\n\t"
  190.                 "NORTPATCH     : %s\n\tIMAGES        : %s\n\t"
  191.                 "QUALITY       : %s\n\tIMG_YES       : %s\n\tIMG_NO        : %s\n\t"
  192.                 "IMG_CANCEL    : %s\n\tIBUTTONSBYTEXT: %s\n\tSINGLE_IS_OK  : %s\n\t"
  193.                 "AFTERPATCH    : %s\n\tAVOIDTASKS    : %s\n\n",
  194.         VersionString+6,
  195.         ConfigName,
  196.         ttVars.MousedReq            ? true_s : false_s,
  197.         ttVars.SameWidthButtons    ? true_s : false_s,
  198.         ttVars.FrontmostScreen    ? true_s : false_s,
  199.         ttVars.Transparency        ? true_s : false_s,
  200.         ttVars.SingleFrame        ? true_s : false_s,
  201.         ttVars.Sizeable            ? true_s : false_s,
  202.         ttVars.Centered            ? true_s : false_s,
  203.         ttVars.NoRTPatch            ? true_s : false_s,
  204.         ttVars.DefImageDir,
  205.         (ttVars.Quality==MUIV_Guigfx_Quality_Best) ? "Best" : 
  206.         (ttVars.Quality==MUIV_Guigfx_Quality_Medium) ? "Medium" : 
  207.         (ttVars.Quality==MUIV_Guigfx_Quality_High) ? "High" : "Low",
  208.         ttVars.IB_Yes        ? ttVars.IB_Yes    : none_s,
  209.         ttVars.IB_No        ? ttVars.IB_No        : none_s,
  210.         ttVars.IB_Cancel    ? ttVars.IB_Cancel: none_s,
  211.         ttVars.IButtonsByText    ? ttVars.IButtonsByText    : unset_s,
  212.         ttVars.SingleIsOK            ? true_s : false_s,
  213.         ttVars.AfterPatch            ? ttVars.AfterPatch        : unset_s,
  214.         ttVars.AvoidTasks            ? ttVars.AvoidTasks        : unset_s
  215.         );
  216.  
  217.     if(OpenLibs())
  218.     {
  219.         if(Config = ReadMRQConfig(ConfigName))
  220.         {
  221.             if(MainPort = CreateMsgPort())
  222.             {
  223.                 MainPort->mp_Node.ln_Name = (STRPTR)MRQRendezvousPort;
  224.                 MainPort->mp_Node.ln_Pri = -128;
  225.                 AddPort(MainPort);
  226.  
  227.                 if(BuildApp())
  228.                 {
  229.                 ULONG sigs, result;
  230.                 BOOL running=TRUE;
  231.                 struct MsgPort *RexxRPort;
  232.         
  233.                     if(CreateCustomClasses())
  234.                     {
  235.                         if(RexxRPort = CreateMsgPort())
  236.                         {
  237.                         LONG RexxMPending=0,    RexxPortSignal, MainPortSignal;
  238.             
  239.                             RexxPortSignal = 1<<(RexxRPort->mp_SigBit);
  240.                             MainPortSignal = 1<<(MainPort->mp_SigBit);
  241.  
  242.                             OldEasyRequestArgs = SetFunction((struct Library*)IntuitionBase,EASYREQUESTARGS_OFFSET,(APTR)(&EasyRequestArgsPatch));
  243.                             prdebug("SetFunction() called on %s\n","intuition.library/EasyRequestArgs()");
  244.                             if(ReqToolsBase)                // obviously, only patch if RT found
  245.                             {
  246.                                 if(ttVars.NoRTPatch)        // if no reqtools patching desired
  247.                                 {
  248.                                     CloseLibrary((struct Library*)ReqToolsBase);    // close early
  249.                                     ReqToolsBase = NULL;
  250.                                 } else
  251.                                 {
  252.                                     OldrtEZRequestA = SetFunction((struct Library*)ReqToolsBase,RTEZREQUESTA_OFFSET,(APTR)(&rtEZRequestA_Wedge));
  253.                                     prdebug("SetFunction() called on %s\n","reqtools.library/rtEZRequestA()");
  254.                                 }
  255.                             }
  256.  
  257.                             if(ttVars.AfterPatch) StartExternalProgram(ttVars.AfterPatch);
  258.                             
  259.                             prdebug("Entering main loop\n\n");
  260.                             while(running)
  261.                             {
  262.                                 result = DoMethod(Application,MUIM_Application_NewInput,&sigs);
  263.             
  264.                                 switch(result)
  265.                                 {
  266.                                     case MUIV_Application_ReturnID_Quit :
  267.                                         running = !AskQuit();
  268.                                         break;
  269.             
  270.                                     default :
  271.                                         if(result && (!(result & 0x01)))
  272.                                         {
  273.                                         struct MRQReqMessage *msg;
  274.  
  275.                                             msg = (struct MRQReqMessage*)result;
  276.  
  277.                                             if(msg->mrm_EventHandler)
  278.                                             {
  279.                                                 DoMethod(msg->mrm_WindowObject,
  280.                                                             MUIM_Window_RemEventHandler,
  281.                                                             msg->mrm_EventHandler);
  282.                                             }
  283.                                             DoMethod(Application,OM_REMMEMBER,msg->mrm_WindowObject);
  284.                                             DisposeObject(msg->mrm_WindowObject);
  285.                                             ReplyMsg((struct Message*)msg);
  286.                                         }
  287.                                 }
  288.                                 if(sigs)
  289.                                 {
  290.                                     sigs = Wait(sigs | RexxPortSignal | MainPortSignal | SIGBREAKF_CTRL_C);
  291.  
  292.                                     if(sigs & SIGBREAKF_CTRL_C)    // got break signal
  293.                                     {
  294.                                         prdebug("Ctrl-C received\n");
  295.                                         running = FALSE;
  296.                                         continue;
  297.                                     }
  298.  
  299.                                     if(sigs & MainPortSignal)        // have to set up a new requester
  300.                                     {
  301.                                     struct MRQReqMessage *msg;
  302.  
  303.                                         if(!(msg = (struct MRQReqMessage*)GetMsg(MainPort)))
  304.                                         {
  305.                                             DisplayBeep(NULL);
  306.                                             continue;
  307.                                         }
  308.  
  309.                                         MUI_EasyRequestArgs(msg);        // setup the entire requester
  310.  
  311.                                         if(msg->mrm_FatalError)            // handle errors
  312.                                         {
  313.                                             ReplyMsg((struct Message*)msg);
  314.                                             continue;
  315.                                         }
  316.  
  317.                                         if(msg->mrm_ARexxCmd)            // have to dispatch an ARexx command
  318.                                         {
  319.                                         struct RexxMsg *rmsg;
  320.  
  321.                                             prdebug("Sending ARexx message:\n\tPORT: '%s'\n\tCMND: '%s'...",msg->mrm_ARexxPort,msg->mrm_ARexxCmd);
  322.         
  323.                                             if(rmsg = CreateRexxMsg(RexxRPort,NULL,msg->mrm_ARexxPort))
  324.                                             {
  325.                                                 rmsg->rm_Action    = RXCOMM;
  326.                                                 rmsg->rm_Args[0]    = msg->mrm_ARexxCmd;
  327.                                                 if(FillRexxMsg(rmsg,1,0))
  328.                                                 {
  329.                                                 struct MsgPort *RxDestPort;
  330.  
  331.                                                     Forbid();
  332.                                                     if(RxDestPort = FindPort(msg->mrm_ARexxPort))
  333.                                                     {
  334.                                                         PutMsg(RxDestPort,(struct Message*)rmsg);
  335.                                                         RexxMPending++;
  336.                                                         Permit();
  337.                                                         prdebug("OK!\n");
  338.                                                     } else
  339.                                                     {
  340.                                                         Permit();
  341.                                                         prdebug("port not found!\n");
  342.                                                     }
  343.                                                 } else prdebug("FillRexxMsg() failed!\n");
  344.                                             } else prdebug("can't create rexx message!\n");
  345.                                         }
  346.                                     }
  347.  
  348.                                     if(sigs & RexxPortSignal)        // got ARexx demon reply
  349.                                     {
  350.                                     struct RexxMsg *rmsg;
  351.             
  352.                                         while(rmsg = (struct RexxMsg*)GetMsg(RexxRPort))
  353.                                         {
  354.                                             ClearRexxMsg(rmsg,1);
  355.                                             DeleteRexxMsg(rmsg);
  356.                                             RexxMPending--;
  357.                                             prdebug("Rexxhost reply received\n");
  358.                                         }
  359.                                     }
  360.                                 }
  361.                             }
  362.  
  363.                             if(ReqToolsBase)
  364.                             {
  365.                                 SetFunction((struct Library*)ReqToolsBase,RTEZREQUESTA_OFFSET,OldrtEZRequestA);
  366.                                 prdebug("rtEZRequestA()-patch removed\n");
  367.                             }
  368.                             SetFunction((struct Library*)IntuitionBase,EASYREQUESTARGS_OFFSET,OldEasyRequestArgs);
  369.                             prdebug("EasyRequestArgs()-patch removed\n");
  370.                             while(RexxMPending)
  371.                             {
  372.                                 WaitPort(RexxRPort);
  373.                                 GetMsg(RexxRPort);
  374.                             }
  375.                             DeleteMsgPort(RexxRPort);
  376.                         } else
  377.                         {
  378.                             prdebug("Can't create ARexx communication port!\n");
  379.                             rcode=RETURN_FAIL;
  380.                         }
  381.                         DeleteCustomClasses();
  382.                     } else
  383.                     {
  384.                         prdebug("Can't create custom classes!\n");
  385.                         rcode=RETURN_FAIL;
  386.                     }
  387.                     DisposeApp(Application);        
  388.                     prdebug("Disposed of MUI app\n");
  389.                 } else
  390.                 {
  391.                     prdebug("Can't build MUI application object!\n");
  392.                     rcode=RETURN_FAIL;
  393.                 }
  394.                 RemPort(MainPort);
  395.                 DeleteMsgPort(MainPort);
  396.             }
  397.             FreeMRQConfig(Config);
  398.         } else rcode=RETURN_FAIL;
  399.         CloseLibs();
  400.     } else rcode=RETURN_FAIL;
  401.  
  402.     if(_debugfh)                                        // debug output being printed
  403.     {
  404.         if(strlen(ttVars.Debug) || !argc)        // file specified or WB-start
  405.             Close(_debugfh);
  406.     }
  407.  
  408.     if(argc) FreeArgs((struct RDArgs*)Args);
  409.     else FreeDiskObject((struct DiskObject*)Args);
  410.  
  411.     MyProc->pr_WindowPtr = MyWindowPtr;
  412.  
  413.     return rcode;
  414. }
  415.  
  416. /*************************************************************************/
  417.  
  418. static BOOL OpenLibs(void)
  419. {
  420. struct EasyStruct es={sizeof(struct EasyStruct),0,"MRQ Error","Can't open %s V%ld+!","Dammit!"};
  421.  
  422.     ReqToolsBase = (struct ReqToolsBase*)OpenLibrary(REQTOOLSLIB_NAME, REQTOOLSLIB_VMIN);    // optional
  423.     CyberGfxBase = OpenLibrary(CGFXLIB_NAME,CGFXLIB_VMIN);             // optional
  424.     if(MUIMasterBase = OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN))
  425.     {
  426.         if(GuiGFXBase = OpenLibrary(GUIGFXLIB_NAME,GUIGFXLIB_VMIN))
  427.         {
  428.             return TRUE;
  429.         } else
  430.         {
  431.             EasyRequest(NULL,&es,NULL,GUIGFXLIB_NAME,GUIGFXLIB_VMIN);
  432.             CloseLibs();
  433.         }
  434.     } else
  435.     {
  436.         EasyRequest(NULL,&es,NULL,MUIMASTER_NAME,MUIMASTER_VMIN);
  437.     }
  438.     return FALSE;    
  439. }
  440.  
  441. static void CloseLibs(void)
  442. {
  443.     if(MUIMasterBase) CloseLibrary(MUIMasterBase);
  444.     if(ReqToolsBase) CloseLibrary((struct Library*)ReqToolsBase);
  445. }
  446.  
  447. /*************************************************************************/
  448.  
  449. static BOOL BuildApp(void)
  450. {
  451.     Application = ApplicationObject,
  452.         MUIA_Application_Title      , "MRQ",
  453.         MUIA_Application_Version    , VersionString,
  454.         MUIA_Application_Copyright  , "Matthias Bethke",
  455.         MUIA_Application_Author     , "Matthias Bethke",
  456.         MUIA_Application_Description, "A requester replacement using MUI",
  457.         MUIA_Application_Base       , "MRQ",
  458.         MUIA_Application_SingleTask , TRUE,
  459.         MUIA_Application_BrokerHook , &BrokerHook,
  460.         End;
  461.  
  462.     if(Application)
  463.     {
  464.         DoMethod(Application,MUIM_Notify,MUIA_Application_Active,MUIV_EveryTime,
  465.                     MUIV_Notify_Self,3,MUIM_WriteLong,MUIV_TriggerValue,&AppActive);
  466.     }
  467.     return (BOOL)Application;
  468. }
  469.  
  470.  
  471. static void DisposeApp(APTR app)
  472. {
  473.     if(app) MUI_DisposeObject(app);
  474. }
  475.  
  476. /*************************************************************************/
  477.  
  478. static APTR ReadToolTypes(struct WBStartup *msg)
  479. {
  480. struct DiskObject *dob;
  481. BPTR olddir=0, homedir;
  482.  
  483.     if(!(msg->sm_NumArgs)) return NULL;
  484.     homedir = msg->sm_ArgList[0].wa_Lock;
  485.     if(homedir) olddir = CurrentDir(homedir);
  486.  
  487.     if(dob = GetDiskObject(msg->sm_ArgList[0].wa_Name))
  488.     {
  489.         ttVars.ConfigName            = FindToolType(dob->do_ToolTypes,"CONFIGFILE");
  490.         ttVars.Debug                = FindToolType(dob->do_ToolTypes,"DEBUG");
  491.         ttVars.MousedReq            = (LONG)FindToolType(dob->do_ToolTypes,"MOUSEREQ");
  492.         ttVars.SameWidthButtons    = (LONG)FindToolType(dob->do_ToolTypes,"SAMEWIDTH");
  493.         ttVars.FrontmostScreen    = (LONG)FindToolType(dob->do_ToolTypes,"FRONTSCREEN");
  494.         ttVars.SingleFrame        = (LONG)FindToolType(dob->do_ToolTypes,"SINGLEFRAME");
  495.         ttVars.Transparency        = (LONG)FindToolType(dob->do_ToolTypes,"TRANSPARENCY");
  496.         ttVars.Sizeable            = (LONG)FindToolType(dob->do_ToolTypes,"SIZEABLE");
  497.         ttVars.Centered            = (LONG)FindToolType(dob->do_ToolTypes,"CENTERTEXT");
  498.         ttVars.NoRTPatch            = (LONG)FindToolType(dob->do_ToolTypes,"NORTPATCH");
  499.         ttVars.DefaultIcon        = (LONG)FindToolType(dob->do_ToolTypes,"DEFAULTICON");
  500.         ttVars.SingleIsOK            = (LONG)FindToolType(dob->do_ToolTypes,"SINGLE_IS_OK");
  501.         ttVars.DefImageDir        = FindToolType(dob->do_ToolTypes,"IMAGES");
  502.         ttVars.IButtonsByText    = FindToolType(dob->do_ToolTypes,"IBUTTONSBYTEXT");
  503.         ttVars.IB_Yes                = FindToolType(dob->do_ToolTypes,"IMG_YES");
  504.         ttVars.IB_No                = FindToolType(dob->do_ToolTypes,"IMG_NO");
  505.         ttVars.IB_Cancel            = FindToolType(dob->do_ToolTypes,"IMG_CANCEL");
  506.         ttVars.AfterPatch            = FindToolType(dob->do_ToolTypes,"AFTERPATCH");
  507.         ttVars.AvoidTasks            = FindToolType(dob->do_ToolTypes,"AVOIDTASKS");
  508.  
  509.         ttVars.Quality                = DecodeQuality(FindToolType(dob->do_ToolTypes,"QUALITY"));
  510.     } else PrintFault(IoErr(),ProgName);
  511.     if(olddir) CurrentDir(olddir);
  512.     return (APTR)dob;
  513. }
  514.  
  515. static APTR ReadShellParams(void)
  516. {
  517. struct RDArgs *Args;
  518. struct MRQShellArguments args={0};
  519.  
  520.     if(Args = ReadArgs(
  521.         "Configfile,IMD=ImageDir/K,BY=Button_Yes/K,BN=Button_No/K,BC=Button_Cancel/K,"
  522.         "IBBT=IButtonsByText/K,QU=Quality/K,AT=AvoidTasks/K,DI=DefaultIcon/S"
  523.         "MR=MouseReq/S,SW=SameWidth/S,FS=FrontScreen/S,"
  524.         "SF=SingleFrame/S,TR=Transparency/S,SI=Sizeable/S,CT=CenterText/S,NRTP=NoRTPatch/S,"
  525.         "SIOK=SingleIsOK/S,AP=AfterPatch/K,Debug/K",(LONG*)&args,NULL))
  526.     {
  527.         ttVars.ConfigName        = args.ConfigName;    // may be NULL!
  528.  
  529.         ttVars.DefImageDir    = args.DefImageDir    ? args.DefImageDir    : NULL;
  530.         ttVars.IB_Yes            = args.IB_Yes            ? args.IB_Yes            : NULL;
  531.         ttVars.IB_No            = args.IB_No            ? args.IB_No            : NULL;
  532.         ttVars.IB_Cancel        = args.IB_Cancel        ? args.IB_Cancel        : NULL;
  533.         ttVars.IButtonsByText= args.IButtonsByText? args.IButtonsByText: NULL;
  534.         ttVars.Quality            = DecodeQuality(args.Quality);
  535.         ttVars.MousedReq            = args.MousedReq;
  536.         ttVars.SameWidthButtons    = args.SameWidth;
  537.         ttVars.FrontmostScreen    = args.FrontScreen;
  538.         ttVars.SingleFrame        = args.SingleFrame;
  539.         ttVars.Transparency        = args.Transparency;
  540.         ttVars.Sizeable            = args.Sizeable;
  541.         ttVars.Centered            = args.Centered;
  542.         ttVars.NoRTPatch            = args.NoRTPatch;
  543.         ttVars.AfterPatch            = args.AfterPatch;
  544.         ttVars.Debug                = args.Debug;
  545.         ttVars.AvoidTasks            = args.AvoidTasks;
  546.         ttVars.DefaultIcon        = args.DefaultIcon;
  547.         ttVars.SingleIsOK            = args.SingleIsOK;
  548.     } else PrintFault(IoErr(),ProgName);
  549.     return (APTR)Args;
  550. }
  551.  
  552. /*************************************************************************/
  553.  
  554. static void __saveds __asm __interrupt BrokerHookFunc(register __a1 CxMsg *cxm, register __a2 APTR app)
  555. {
  556.     if(CxMsgType(cxm) == CXM_COMMAND)
  557.     {
  558.         if(CxMsgID(cxm) == CXCMD_APPEAR)
  559.         {
  560.             if(MUI_RequestA(Application,NULL,0,"MRQ Request","*_MUIprefs|_Configfile",
  561.                                     "Edit MUI settings for MRQ\nor edit the configfile?",
  562.                                     NULL))
  563.             {
  564.                 DoMethod(app,MUIM_Application_OpenConfigWindow,0);
  565.             } else prdebug("Configfile editing not yet implemented!\n");
  566.         }
  567.     }
  568. }
  569.  
  570. /*************************************************************************/
  571.  
  572.  
  573. static LONG DecodeQuality(STRPTR s)
  574. {
  575.     if(s)
  576.     {
  577.         if(!stricmp(s,"best")) return MUIV_Guigfx_Quality_Best;
  578.         if(!stricmp(s,"high")) return MUIV_Guigfx_Quality_High;
  579.         if(!stricmp(s,"low")) return MUIV_Guigfx_Quality_Low;
  580.     }
  581.     return MUIV_Guigfx_Quality_Medium;        // default
  582. }
  583.  
  584.  
  585. /*************************************************************************/
  586.  
  587. static void StartExternalProgram(STRPTR ttype)
  588. {
  589. BPTR FileLock;
  590. BOOL WBStarted=FALSE;
  591.  
  592.     if(FileLock = Lock(ttype,ACCESS_READ))
  593.     {
  594.     BPTR DirLock;
  595.  
  596.         DirLock = ParentDir(FileLock);
  597.         UnLock(FileLock);
  598.         if(ExistsIcon(ttype))
  599.         {
  600.         struct Library *WBStartBase;
  601.  
  602.             if(WBStartBase = OpenLibrary("wbstart.library",0))
  603.             {
  604.                 prdebug("Starting Workbench program '%s'\n",ttype);
  605.  
  606.                 if(WBStartTags(WBStart_Name, ttype,
  607.                                     WBStart_DirectoryLock, DirLock,
  608.                                     TAG_DONE) == RETURN_OK)
  609.                 {
  610.                     WBStarted = TRUE;
  611.                 } else
  612.                 {
  613.                     prdebug("Error starting program!\n");
  614.                 }
  615.                 CloseLibrary(WBStartBase);
  616.             } else prdebug("Starting Workbench programs requires %s\n","wbstart.library");
  617.         }
  618.     }
  619.  
  620.     if(!WBStarted)
  621.     {
  622.     STRPTR tt,prog,args;
  623.  
  624.         if(tt = AllocVecPooled(Config->mc_MemPool,strlen(ttype)+1))
  625.         {
  626.             strcpy(tt,ttype);
  627.  
  628.             prog = strtok(tt," ");
  629.             args = strtok(NULL," ");
  630.  
  631.             prdebug("Starting shell program \"%s\" (parameters: \"%s\")\n",prog,args?args:(STRPTR)"<none>");
  632.  
  633.             if(SystemTags(prog,
  634.                                 NP_Arguments,args,
  635.                                 SYS_Asynch,TRUE,
  636.                                 TAG_DONE) != RETURN_OK)
  637.             {
  638.                 prdebug("Error starting program!\n");
  639.             }
  640.             FreeVecPooled(Config->mc_MemPool,tt);
  641.         }
  642.     }
  643. }
  644.  
  645. static BOOL ExistsIcon(STRPTR prog)
  646. {
  647. STRPTR icon;
  648. ULONG proglen;
  649. BOOL ret = FALSE;
  650.  
  651.     proglen = strlen(prog);
  652.     if(icon = AllocVecPooled(Config->mc_MemPool,proglen+6))
  653.     {
  654.     BPTR lock;
  655.  
  656.         strcpy(icon,prog);
  657.         strcpy(icon+proglen,".info");
  658.         if(lock = Lock(icon,ACCESS_READ))
  659.         {
  660.             UnLock(lock);
  661.             ret = TRUE;
  662.         }
  663.         FreeVecPooled(Config->mc_MemPool,icon);
  664.     }
  665.     return ret;
  666. }
  667.  
  668. /*************************************************************************/
  669.  
  670. static STRPTR FindConfigFile(void)
  671. {
  672. static STRPTR CfgAlts[3] = {NULL,"PROGDIR:MRQ.config","s:MRQ.config"};
  673. BPTR lock;
  674. int i;
  675.  
  676.     i = (CfgAlts[0] = ttVars.ConfigName) ? 0 : 1;
  677.     for(; i<(sizeof(CfgAlts)/sizeof(STRPTR)); i++)
  678.     {
  679.         if(lock=Lock(CfgAlts[i],ACCESS_READ))
  680.         {
  681.             UnLock(lock);
  682.             return CfgAlts[i];
  683.         }
  684.     }
  685.     return NULL;
  686. }
  687.  
  688. static BOOL CheckDir(STRPTR dir)
  689. {
  690. BPTR lock;
  691. BOOL ret=FALSE;
  692.  
  693.     if(lock=Lock(dir,ACCESS_READ))
  694.     {
  695.     struct FileInfoBlock *fib;
  696.         if(fib = AllocDosObjectTagList(DOS_FIB,NULL))
  697.         {
  698.             if(Examine(lock,fib))
  699.             {
  700.                 if(fib->fib_DirEntryType > 0) ret=TRUE;    // entry is directory
  701.             }
  702.             FreeDosObject(DOS_FIB,fib);
  703.         }
  704.         UnLock(lock);
  705.     }
  706.     return ret;
  707. }
  708.  
  709. static BOOL AskQuit(void)
  710. {
  711.  
  712.     if(CheckPatchManager()) return TRUE;    // don't ask if it's safe to remove patches
  713.  
  714.     if(ttVars.AfterPatch)
  715.     {
  716.         MUI_RequestA(Application,NULL,0,"MRQ Error","*:-(",
  717.             "MRQ has started another program after patching!\n"
  718.             "Therefore it can't be unloaded without causing\n"
  719.             "a certain crash on the next call to a patched function.",NULL);
  720.         return FALSE;
  721.     }
  722.     return (BOOL)MUI_RequestA(Application,NULL,0,"MRQ Warning","_I am sure|*_Not really",
  723.                         "Are you sure you want to quit MRQ?\n"
  724.                         "This is not safe if other programs have\n"
  725.                         "patched the same functions!",NULL);
  726. }
  727.  
  728. static BOOL CheckPatchManager(void)
  729. {
  730. BOOL ret;
  731.  
  732.     Forbid();
  733.     ret = (BOOL)(FindPort("SetMan"));
  734.     Permit();
  735.     return ret;
  736. }
  737.  
  738. static BOOL CreateCustomClasses(void)
  739. {
  740.     if(MUIMRQWindowClass = NewMRQWindowClass())
  741.     {
  742.         MRQWindowClass = MUIMRQWindowClass->mcc_Class;
  743.         return TRUE;
  744.     }
  745.     DeleteCustomClasses();
  746.     return FALSE;
  747. }
  748.  
  749. static void DeleteCustomClasses(void)
  750. {
  751.     if(MUIMRQWindowClass)    MUI_DeleteCustomClass(MUIMRQWindowClass);
  752. }
  753.  
  754.  
  755.  
  756. void prdebug(char *fmt, ...)
  757. {
  758. va_list arglist;
  759. char tbuf[768];
  760.  
  761.     if(ttVars.Debug)
  762.     {
  763.         memset(tbuf,0,sizeof(tbuf));
  764.         va_start(arglist,fmt);
  765.         mb_VNSPrintf(tbuf,fmt,sizeof(tbuf),(LONG*)arglist);
  766.         FPuts(_debugfh,tbuf);
  767.         va_end(arglist);
  768.     }
  769. }
  770.